﻿using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using PasteTimer.slavemodels;
using PasteTimer.taskmodels;
using Volo.Abp.DependencyInjection;
using Volo.Abp.ObjectMapping;

namespace PasteTimer
{
    /// <summary>
    /// 
    /// </summary>
    public class ModelHelper : ISingletonDependency
    {
        private readonly IAppCache _cache;
        private readonly IObjectMapper _mapper;
        private readonly IServiceProvider _serviceProvider;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="cache"></param>
        /// <param name="mapper"></param>
        /// <param name="serviceProvider"></param>
        public ModelHelper(IAppCache cache, IObjectMapper mapper, IServiceProvider serviceProvider)
        {
            _cache = cache;
            _mapper = mapper;
            _serviceProvider = serviceProvider;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<SlaveInfoDto> SlaveInfoDtoItem(int id)
        {
            var itemkey = string.Format(PublicString.CacheItemSlaveInfo, id);
            var item = await _cache.ReadObject<SlaveInfoDto>(itemkey);
            if (item == null || item == default)
            {
                using var scope = _serviceProvider.CreateScope();
                using var _dbContext = scope.ServiceProvider.GetRequiredService<IPasteTimerDbContext>();
                var one = _dbContext.NodeInfo.Where(x => x.Id == id).AsNoTracking().FirstOrDefault();
                if (one != null && one != default)
                {
                    var onedto = _mapper.Map<NodeInfo, SlaveInfoDto>(one);
                    _cache.SetObject<SlaveInfoDto>(itemkey, onedto, 1600);
                    return onedto;
                }
                return null;
            }
            else
            {
                return item;
            }
        }

        /// <summary>
        /// 删除对象
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public int SlaveInfoDtoRemove(int id)
        {
            var itemkey = string.Format(PublicString.CacheItemSlaveInfo, id);
            _cache.RemoveKey(itemkey);
            return 1;
        }

        /// <summary>
        /// 收集统计信息
        /// </summary>
        /// <param name="taskid"></param>
        /// <param name="type"></param>
        public void CollectData(int taskid, CollectType type)
        {
            var now = DateTime.Now;
            var _type = "run";
            switch (type)
            {
                case CollectType.run: _type = "run"; break;
                case CollectType.fail: _type = "fail"; break;
                case CollectType.okay: _type = "okay"; break;
            }
            _cache.HashIncrementAsync(PublicString.CollectHourHashKey, string.Format(PublicString.CollectFieldFormat, $"{now.ToString("yyyyMMddHH")}", taskid, _type));
            _cache.HashIncrementAsync(PublicString.CollectDailyHashKey, string.Format(PublicString.CollectFieldFormat, $"{now.ToString("yyyyMMdd")}", taskid, _type));
            _cache.HashIncrementAsync(PublicString.CollectMonthHashKey, string.Format(PublicString.CollectFieldFormat, $"{now.ToString("yyyyMM")}", taskid, _type));
        }

        /// <summary>
        /// 获取我的任务列表
        /// </summary>
        /// <param name="_dbContext"></param>
        /// <param name="userid"></param>
        /// <returns></returns>
        public IQueryable<int> QueryableMyTaskId(IPasteTimerDbContext _dbContext,int userid)
        {
            //var _query = _dbContext.TaskBindUser.Where(x => x.UserId == userid).Select(x => x.TaskId);
            //return _query;
            var _query_taskid = _dbContext.TaskBindUser.Where(x => x.UserId == userid).Select(x => x.TaskId);
            var taskids = _dbContext.TaskInfo.Where(x => x.UserId == 0 || _query_taskid.Contains(x.Id)).Select(x => x.Id);
            return taskids;
        }

        /// <summary>
        /// 获取我的任务列表
        /// </summary>
        /// <param name="_dbContext"></param>
        /// <param name="userid"></param>
        /// <returns></returns>
        public int[] MyTaskIdArray(IPasteTimerDbContext _dbContext, int userid)
        {
            var _query_taskid = _dbContext.TaskBindUser.Where(x => x.UserId == userid).Select(x => x.TaskId);
            var taskids = _dbContext.TaskInfo.Where(x => x.UserId == 0 || _query_taskid.Contains(x.Id)).Select(x => x.Id).ToArray();
            return taskids;
        }

        /// <summary>
        /// 判断我是否有某一个任务的权限
        /// </summary>
        /// <param name="_dbContext"></param>
        /// <param name="userid"></param>
        /// <param name="taskid"></param>
        /// <returns></returns>
        /// <exception cref="PasteTimerException"></exception>
        public bool HasTaskException(IPasteTimerDbContext _dbContext, int userid,int taskid)
        {
            var _query = _dbContext.TaskBindUser.Where(x => x.UserId == userid && x.TaskId == taskid).Select(x => x.Id).FirstOrDefault();//.Select(x => x.TaskId);
            if (_query != 0)
            {
                return true;
            }
            else
            {
                throw new PasteTimerException($"没有任务:{taskid}的权限，请先绑定后再试！");
            }
        }

        /// <summary>
        /// 计算轮询秒数
        /// 如果正则是00:00:00的格式表示时分秒也就是最大支持99:99:99
        /// </summary>
        /// <param name="info"></param>
        /// <exception cref="Exception"></exception>
        public void ReadTickSecond(TaskInfo info)
        {
            if (!string.IsNullOrEmpty(info.TickRegex))
            {
                if (info.TickRegex.Length == 8)
                {
                    var timesplit = info.TickRegex.Split(":");
                    if (timesplit.Length == 3)
                    {
                        int.TryParse(timesplit[0], out var hour);
                        int.TryParse(timesplit[1], out var min);
                        int.TryParse(timesplit[2], out var sec);
                        info.TickSecond = (hour * 3600) + (min * 60) + sec;
                        info.TaskType = TaskType.Tick;
                    }
                }
            }
        }

    }

    public enum CollectType
    {
        run = 1,
        fail = 2,
        okay = 3
    }
}
